using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using Microsoft.Practices.RecipeFramework.Library;
using Microsoft.VisualStudio.TextTemplating;

namespace PrismFactory.SoftwareFactory.Actions.Temp
{
    internal class PropertiesDirectiveProcessor : DirectiveProcessor
    {
        // Fields
        private StringWriter codeWriter;
        private const string ConverterAttribute = "converter";
        private const string EditorAttribute = "editor";
        private TemplateHost host;
        private CodeDomProvider languageProvider;
        private const string NameAttribute = "name";
        private const string PropertyDirectiveName = "property";
        private const string PropertyDirectiveProcessorName = "PropertyProcessor";
        private const string TypeAttribute = "type";

        // Methods
        public override void FinishProcessingRun()
        {
        }

        public override string GetClassCodeForProcessingRun()
        {
            if (codeWriter == null)
            {
                throw new InvalidOperationException("PropertiesDirectiveProcessor_StartProcessingRunNotInvoked");
            }
            return codeWriter.ToString();
        }

        public override string[] GetImportsForProcessingRun()
        {
            return null;
        }

        public override string GetPostInitializationCodeForProcessingRun()
        {
            return null;
        }

        public override string GetPreInitializationCodeForProcessingRun()
        {
            return null;
        }

        public override string[] GetReferencesForProcessingRun()
        {
            return new[] {base.GetType().Assembly.Location};
        }

        public override void Initialize(ITextTemplatingEngineHost host)
        {
            base.Initialize(host);
            if (host == null)
            {
                throw new ArgumentNullException("host");
            }
            this.host = (TemplateHost) host;
        }

        public override bool IsDirectiveSupported(string directiveName)
        {
            if (directiveName == null)
            {
                throw new ArgumentNullException("directiveName");
            }
            return (string.Compare(directiveName, "property", StringComparison.OrdinalIgnoreCase) == 0);
        }

        public override void ProcessDirective(string directiveName, IDictionary<string, string> arguments)
        {
            Guard.ArgumentNotNull(directiveName, "directiveName");
            Guard.ArgumentNotNull(arguments, "arguments");
            if (string.Compare(directiveName, "property", true) == 0)
            {
                if (!host.Arguments.ContainsKey(arguments["name"]))
                {
                    throw new ArgumentNullException(arguments["name"], string.Format(CultureInfo.CurrentCulture, "PropertiesDirectiveProcessor_UndefinedValue", new object[] {"name"}));
                }
                var member = new CodeMemberProperty();
                member.Name = arguments["name"];
                if (arguments.ContainsKey("type"))
                {
                    member.Type = new CodeTypeReference(arguments["type"]);
                }
                else
                {
                    member.Type = new CodeTypeReference(host.Arguments[member.Name].Type);
                }
                if (arguments.ContainsKey("converter"))
                {
                    member.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof (TypeConverterAttribute)), new[] {new CodeAttributeArgument(new CodeTypeOfExpression(arguments["converter"]))}));
                }
                if (arguments.ContainsKey("editor"))
                {
                    member.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof (EditorAttribute)), new[] {new CodeAttributeArgument(new CodeTypeOfExpression(arguments["editor"]))}));
                }
                member.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                member.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof (TemplatePropertyAttribute))));
                member.GetStatements.Add(new CodeMethodReturnStatement(new CodeCastExpression(member.Type, new CodePropertyReferenceExpression(new CodeIndexerExpression(new CodePropertyReferenceExpression(new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(typeof (TemplateHost)), "CurrentHost"), "Arguments"), new CodeExpression[] {new CodePrimitiveExpression(member.Name)}), "Value"))));
                var options = new CodeGeneratorOptions();
                options.BracingStyle = "C";
                languageProvider.GenerateCodeFromMember(member, codeWriter, options);
            }
        }

        public override void StartProcessingRun(CodeDomProvider languageProvider, string templateContents, CompilerErrorCollection errors)
        {
            base.StartProcessingRun(languageProvider, templateContents, errors);
            if (languageProvider == null)
            {
                throw new ArgumentNullException("languageProvider");
            }
            codeWriter = new StringWriter(CultureInfo.CurrentCulture);
            this.languageProvider = languageProvider;
        }
    }
}